home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Visual Cafe 3
/
Visual Cafe 3.ISO
/
Vcafe
/
JFC.bin
/
JTable.java
< prev
next >
Wrap
Text File
|
1998-06-30
|
137KB
|
3,742 lines
/*
* @(#)JTable.java 1.82 98/04/13
*
* Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the confidential and proprietary information of Sun
* Microsystems, Inc. ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Sun.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
* SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
* SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
* THIS SOFTWARE OR ITS DERIVATIVES.
*
*/
package com.sun.java.swing;
import java.lang.Thread;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.beans.PropertyChangeListener;
import com.sun.java.accessibility.*;
import com.sun.java.swing.*;
import com.sun.java.swing.event.*;
import com.sun.java.swing.plaf.*;
import com.sun.java.swing.table.*;
import com.sun.java.swing.border.*;
/**
* JTable is a user-interface component that presents data in a two-dimensional
* table format. The JTable has many features that make it possible to
* customize its rendering and editing but provides defaults
* for these features so that simple tables can be set up easily.
* For example, to set up a table with 10 rows and 10 columns of numbers:
* <p>
* <pre>
* TableModel dataModel = new AbstractTableModel() {
* public int getColumnCount() { return 10; }
* public int getRowCount() { return 10;}
* public Object getValueAt(int row, int col) { return new Integer(row*col); }
* };
* JTable table = new JTable(dataModel);
* JScrollPane scrollpane = new JScrollPane(table);
* </pre>
* <p>
* Because the JTable is now much easier to set up with custom models
* the DefaultTableModel is less useful than it was in previous releases.
* Instead of copying the data in an application into the DefaultTableModel,
* we recommend wrapping it in the methods of the TableModel interface and
* passing the real data to the JTable as above. This technique is nearly as concise
* as using a DefaultTableModel and starting this way has a number of advantages
* over the longer term. In particular: it is a scalable technique,
* is easier to handle dynamic or editable tables and often results in much
* more efficient applications because the model is free to choose the
* internal representation that best suits the data.
* <p>
* The "Table" directory in the examples/demo area gives a number of complete
* examples of JTable usage, covering how the JTable can be used to provide
* an editable view of data taken from a database and how to modify the columns
* in the display to use specialized renderers and editors.
* <p>
* The JTable uses integers exclusively to refer to both the rows and the columns
* of the model that it displays. The JTable simply takes a tabular range of cells
* and uses <code>getValueAt(int, int)</code> to retrieve and display the values
* from the model.
* <p>
* If <code>getTableHeader().setReorderingAllowed(boolean)</code> is used to
* enable column reordering columns may be rearranged in the JTable so that the
* view's columns appear in a different order to the columns in the model.
* This does not affect the implementation of the model at all: when the
* columns are reordered, the JTable maintains the new order of the columns
* internally and converts its column indices before querying the model.
* So, when writing a TableModel, it is not necessary to listen for column
* reordering events as the the model will be queried in its own co-ordinate
* system regardless of what is happening in the view.
* In the examples area there is a demonstration of a sorting algorithm making
* use of exactly this technique to interpose yet another co-ordinate system
* where the order of the rows is changed, rather than the order of the columns.
* <p>
* The general rule for the JTable API and the APIs of all its associated classes,
* including the the column model and both the row and column selection models, is:
* methods using integer indices for rows and columns always use the co-ordinate
* system of the view. There are three exceptions to this rule:
* <ul>
* <li> All references to rows and columns in the TableModel
* interface are in the co-ordinate system of the model.
* <li> The index <I>modelIndex</I> in the TableColumn constructors
* refers to the index of the column in the model, not the view.
* <li> All constructors for the TableModelEvent, which describes changes
* that have taken place in a table model, use the co-ordinate system
* of the model.
* </ul>
* The TableColumn provides a slot for holding an identifier or "tag" for each column
* and the JTable and TableColumModel both support <I>getColumn(Object id)</I>
* conveniences for locating columns by their identifier. If no identifier is
* explicitly set, the TableColumn returns its header value (the name of the column)
* as a default. A different identifier, which can be of any type, can be set
* using the TableColumn's <I>setIdentifier()</I> method. All of the JTable's
* functions operate correctly regardless of the type and uniqueness of these
* identifiers.
* <p>
* The <I>convertColumnIndexToView()</I> and
* <I>convertColumnIndexToModel()</I> methods have been provided to
* convert between the two co-ordinate systems but
* they are rarely needed during normal use.
* <p>
* See <a href="http://java.sun.com/docs/books/tutorial/ui/swing/table.html">How to Use Tables</a>
* in <a href="http://java.sun.com/Series/Tutorial/index.html"><em>The Java Tutorial</em></a>
* for further documentation.
* <p>
* For the keyboard keys used by this component in the standard Look and
* Feel (L&F) renditions, see the
* <a href="doc-files/Key-Index.html#JTable">JTable</a> key assignments.
* <p>
* Warning: serialized objects of this class will not be compatible with
* future swing releases. The current serialization support is appropriate
* for short term storage or RMI between Swing1.0 applications. It will
* not be possible to load serialized Swing1.0 objects with future releases
* of Swing. The JDK1.2 release of Swing will be the compatibility
* baseline for the serialized form of Swing objects.
*
*
* @beaninfo
* attribute: isContainer false
*
* @version 1.82 04/13/98
* @author Philip Milne
* @author Alan Chung
*/
public class JTable extends JComponent implements TableModelListener, Scrollable,
TableColumnModelListener, ListSelectionListener, CellEditorListener,
Accessible
{
//
// Static Constants
//
/** Do not auto resize column when table is resized. */
public static final int AUTO_RESIZE_OFF = 0;
/** Auto resize last column only when table is resized */
public static final int AUTO_RESIZE_LAST_COLUMN = 1;
/** Proportionately resize all columns when table is resized */
public static final int AUTO_RESIZE_ALL_COLUMNS = 2;
//
// Instance Variables
//
/** The TableModel of the table */
protected TableModel dataModel;
/** The TableColumnModel of the table */
protected TableColumnModel columnModel;
/** The ListSelectionModel of the table, used to keep track of row selections */
protected ListSelectionModel selectionModel;
/** The TableHeader working with the table */
protected JTableHeader tableHeader;
/** The height of all rows in the table */
protected int rowHeight;
/** The height margin between rows */
protected int rowMargin;
/** The color of the grid */
protected Color gridColor;
/** The table draws horizontal lines between cells if showHorizontalLines is true */
protected boolean showHorizontalLines;
/** The table draws vertical lines between cells if showVerticalLines is true */
protected boolean showVerticalLines;
/**
* This mode value determines if table automatically resizes the
* width the table's columns to take up the entire width of the
* table, and how it does the resizing.
*/
protected int autoResizeMode;
/**
* The table will query the TableModel to build the default
* set of columns if this is true.
*/
protected boolean autoCreateColumnsFromModel;
/** Used by the Scrollable interface to determine the initial visible area */
protected Dimension preferredViewportSize;
/** Row selection allowed in this table */
protected boolean rowSelectionAllowed;
/**
* If this is true, then both a row selection and a column selection
* can be non-empty at the same time, the selected cells are the
* the cells whose row and column are both selected.
*/
protected boolean cellSelectionEnabled;
/** If editing, Component that is handling the editing. */
transient protected Component editorComp;
/**
* The object that overwrites the screen real estate occupied by the
* current cell and allows the user to change those contents.
*/
transient protected TableCellEditor cellEditor;
/** Identifies the column of the cell being edited. */
transient protected int editingColumn;
/** Identifies the row of the cell being edited. */
transient protected int editingRow;
/**
* A table of objects that display the contents of a cell,
* indexed by class.
*/
transient protected Hashtable defaultRenderersByColumnClass;
/**
* A table of objects that display and edit the contents of a cell,
* indexed by class.
*/
transient protected Hashtable defaultEditorsByColumnClass;
/** The foreground color of selected cells */
protected Color selectionForeground;
/** The background color of selected cells */
protected Color selectionBackground;
//
// Constructors
//
/**
* Constructs a default JTable which is initialized with a default
* data model, a default column model, and a default selection
* model.
*
* @see #createDefaultDataModel()
* @see #createDefaultColumnModel()
* @see #createDefaultSelectionModel()
*/
public JTable() {
this(null, null, null);
}
/**
* Constructs a JTable which is initialized with <i>dm</i> as the
* data model, a default column model, and a default selection
* model.
*
* @param dm The data model for the table
* @see #createDefaultColumnModel()
* @see #createDefaultSelectionModel()
*/
public JTable(TableModel dm) {
this(dm, null, null);
}
/**
* Constructs a JTable which is initialized with <i>dm</i> as the
* data model, <i>cm</i> as the column model, and a default selection
* model.
*
* @param dm The data model for the table
* @param cm The column model for the table
* @see #createDefaultSelectionModel()
*/
public JTable(TableModel dm, TableColumnModel cm) {
this(dm, cm, null);
}
/**
* Constructs a JTable which is initialized with <i>dm</i> as the
* data model, <i>cm</i> as the column model, and <i>sm</i> as the
* selection model. If any of the parameters are <b>null</b> this
* method will initialize the table with the corresponding
* default model. The <i>autoCreateColumnsFromModel</i> flag is set
* to false if <i>cm</i> is non-null, otherwise it is set to true
* and the column model is populated with suitable TableColumns
* for the columns in <i>dm</i>.
*
* @param dm The data model for the table
* @param cm The column model for the table
* @param sm The row selection model for the table
* @see #createDefaultDataModel()
* @see #createDefaultColumnModel()
* @see #createDefaultSelectionModel()
*/
public JTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
super();
setLayout(null);
if (cm == null) {
cm = createDefaultColumnModel();
autoCreateColumnsFromModel = true;
}
setColumnModel(cm);
if (sm == null)
sm = createDefaultSelectionModel();
setSelectionModel(sm);
// Set the model last, that way if the autoCreatColumnsFromModel has
// been set above, we will automatically populate an empty columnModel
// with suitable columns for the new model.
if (dm == null)
dm = createDefaultDataModel();
setModel(dm);
initializeLocalVars();
updateUI();
}
/**
* Constructs a JTable with <i>numRows</i> and <i>numColumns</i> of
* empty cells using the DefaultTableModel. The columns will have
* names of the form "A", "B", "C", etc.
*
* @param numRows The number of rows the table holds
* @param numColumns The number of columns the table holds
* @see com.sun.java.swing.table.DefaultTableModel
*/
public JTable(int numRows, int numColumns) {
this(new DefaultTableModel(numRows, numColumns));
}
/**
* Constructs a JTable to display the values in the Vector of Vectors,
* <i>rowData</i>, with column names, <i>columnNames</i>.
* The Vectors contained in <i>rowData</i> should contain the values
* for that row. In other words, the value of the cell at row 1,
* column 5 can be obtained with the following code:
* <p>
* <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
* <p>
* All rows must be of the same length as <i>columnNames</i>.
* <p>
* @param rowData The data for the new table
* @param columnNames Names of each column
*/
public JTable(final Vector rowData, final Vector columnNames) {
this(new AbstractTableModel() {
public String getColumnName(int column) { return columnNames.elementAt(column).toString(); }
public int getRowCount() { return rowData.size(); }
public int getColumnCount() { return columnNames.size(); }
public Object getValueAt(int row, int column) {
return ((Vector)rowData.elementAt(row)).elementAt(column);
}
public boolean isCellEditable(int row, int column) { return true; }
public void setValueAt(Object value, int row, int column) {
((Vector)rowData.elementAt(row)).setElementAt(value, column);
}
});
}
/**
* Constructs a JTable to display the values in the two dimensional array,
* <i>rowData</i>, with column names, <i>columnNames</i>.
* <i>rowData</i> is an Array of rows, so the value of the cell at row 1,
* column 5 can be obtained with the following code:
* <p>
* <pre> rowData[1][5]; </pre>
* <p>
* All rows must be of the same length as <i>columnNames</i>.
* <p>
* @param rowData The data for the new table
* @param columnNames Names of each column
*/
public JTable(final Object[][] rowData, final Object[] columnNames) {
this(new AbstractTableModel() {
public String getColumnName(int column) { return columnNames[column].toString(); }
public int getRowCount() { return rowData.length; }
public int getColumnCount() { return columnNames.length; }
public Object getValueAt(int row, int col) { return rowData[row][col]; }
public boolean isCellEditable(int row, int column) { return true; }
public void setValueAt(Object value, int row, int col) {
rowData[row][col] = value;
}
});
}
/**
* Calls <code>configureEnclosingScrollPane</code>.
*
* @see #configureEnclosingScrollPane
*/
public void addNotify() {
super.addNotify();
configureEnclosingScrollPane();
}
/**
* If the JTable is the viewportView of an enclosing JScrollPane
* (the usual situation), configure this ScrollPane by, amongst other things,
* installing the table's tableHeader as the columnHeaderView of the scrollpane.
* When a JTable is added to a JScrollPane in the usual way,
* using <code>new JScrollPane(myTable)</code>, <code>addNotify</code> is
* called in the JTable (when the table is added to the viewport).
* JTable's <code>addNotify</code> method in turn calls this method
* which is protected so that this default installation procedure can
* be overridden by a subclass.
*
* @see #addNotify
*/
protected void configureEnclosingScrollPane() {
Container p = getParent();
if (p instanceof JViewport) {
Container gp = p.getParent();
if (gp instanceof JScrollPane) {
JScrollPane scrollPane = (JScrollPane)gp;
// Make certain we are the viewPort's view and not, for
// example, the rowHeaderView of the scrollPane -
// an implementor of fixed columns might do this.
JViewport viewport = scrollPane.getViewport();
if (viewport == null || viewport.getView() != this) {
return;
}
scrollPane.setColumnHeaderView(getTableHeader());
scrollPane.getViewport().setBackingStoreEnabled(true);
scrollPane.setBorder(UIManager.getBorder("Table.scrollPaneBorder"));
}
}
}
//
// Static Methods
//
/**
* Equivalent to <code>new JScrollPane(aTable)</code>.
*
* @deprecated As of Swing version 1.0.2,
* replaced by <code>new JScrollPane(aTable)</code>.
*/
static public JScrollPane createScrollPaneForTable(JTable aTable) {
return new JScrollPane(aTable);
}
//
// Table Attributes
//
/**
* Sets the tableHeader working with this JTable to <I>newHeader</I>.
* It is legal to have a <B>null</B> tableHeader.
*
* @param newHeader new tableHeader
* @see #getTableHeader()
* @beaninfo
* description: The JTableHeader instance which renders the column headers.
*/
public void setTableHeader(JTableHeader newHeader) {
if (tableHeader != newHeader) {
// Release the old header
if (tableHeader != null)
tableHeader.setTable(null);
tableHeader = newHeader;
if (tableHeader != null)
tableHeader.setTable(this);
}
}
/**
* Returns the tableHeader working with this JTable.
*
* @return the tableHeader working with the receiver
* @see #setTableHeader()
*/
public JTableHeader getTableHeader() {
return tableHeader;
}
/**
* Sets the height for rows to <I>newRowHeight</I> and invokes tile
*
* @param newRowHeight new row height
* @exception IllegalArgumentException If <I>newRowHeight</I> is
* less than 1.
* @see #getRowHeight()
* @beaninfo
* description: The height of the cells including the inter-cell spacing.
*/
public void setRowHeight(int newHeight) {
if (newHeight <= 0) {
throw new IllegalArgumentException("New row height less than 1");
}
rowHeight = newHeight;
resizeAndRepaint();
}
/**
* Returns the height of a table row in the receiver.
* The default row height is 16.0.
*
* @return the height of each row in the receiver
* @see #setRowHeight()
*/
public int getRowHeight() {
return rowHeight;
}
/**
* Sets the width and height between cells to <I>newSpacing</I> and
* redisplays the receiver.
*
* @param newSpacing The new width and height intercellSpacing
* @see #getIntercellSpacing()
* @beaninfo
* description: The spacing between the cells, drawn in the background color of the JTable.
*/
public void setIntercellSpacing(Dimension newSpacing) {
// Set the rowMargin here and columnMargin in the TableColumnModel
rowMargin = newSpacing.height;
getColumnModel().setColumnMargin(newSpacing.width);
resizeAndRepaint();
}
/**
* Returns the horizontal and vertical spacing between cells.
* The default spacing is (3, 2).
*
* @return the horizontal and vertical spacing between cells
* @see #setIntercellSpacing()
*/
public Dimension getIntercellSpacing() {
return new Dimension(getColumnModel().getColumnMargin(), rowMargin);
}
/**
* Sets the color used to draw grid lines to <I>color</I> and redisplays
* the receiver.
* The default color is gray.
*
* @param color new color of the grid
* @exception IllegalArgumentException if <I>color</I> is null
* @see #getGridColor()
*/
public void setGridColor(Color newColor) {
if (newColor == null) {
throw new IllegalArgumentException("New color is null");
}
gridColor = newColor;
// Redraw
repaint();
}
/**
* Returns the color used to draw grid lines. The default color is gray.
*
* @return the color used to draw grid lines
* @see #setGridColor()
*/
public Color getGridColor() {
return gridColor;
}
/**
* Sets whether the receiver draws grid lines around cells.
* If <I>flag</I> is true it does; if it is false it doesn't.
* There is no getShowGrid() method as the this state is held
* in two variables: showHorizontalLines and showVerticalLines
* each of which may be queried independently.
*
* @param flag true if table view should draw grid lines
*
* @see #setShowVerticalLines
* @see #setShowHorizontalLines
* @beaninfo
* description: The color used to draw the grid lines.
*/
public void setShowGrid(boolean b) {
setShowHorizontalLines(b);
setShowVerticalLines(b);
// Redraw
repaint();
}
/**
* Sets whether the receiver draws horizontal lines between cells.
* If <I>flag</I> is true it does; if it is false it doesn't.
*
* @param flag true if table view should draw horizontal lines
* @see #getShowHorizontalLines
* @see #setShowGrid
* @see #setShowVerticalLines
* @beaninfo
* description: Whether horizontal lines should be drawn in between the cells.
*/
public void setShowHorizontalLines(boolean b) {
showHorizontalLines = b;
// Redraw
repaint();
}
/**
* Sets whether the receiver draws vertical lines between cells.
* If <I>flag</I> is true it does; if it is false it doesn't.
*
* @param flag true if table view should draw vertical lines
* @see #getShowVerticalLines
* @see #setShowGrid
* @see #setShowHorizontalLines
* @beaninfo
* description: Whether vertical lines should be drawn in between the cells.
*/
public void setShowVerticalLines(boolean b) {
showVerticalLines = b;
// Redraw
repaint();
}
/**
* Returns true if the receiver draws horizontal lines between cells, false if it
* doesn't. The default is true.
*
* @return true if the receiver draws horizontal lines between cells, false if it
* doesn't
* @see #setShowHorizontalLines
*/
public boolean getShowHorizontalLines() {
return showHorizontalLines;
}
/**
* Returns true if the receiver draws vertical lines between cells, false if it
* doesn't. The default is true.
*
* @return true if the receiver draws vertical lines between cells, false if it
* doesn't
* @see #setShowVerticalLines
*/
public boolean getShowVerticalLines() {
return showVerticalLines;
}
/**
* Sets the table's auto resize mode when the table is resized.
*
* @param mode One of 3 legal values: AUTO_RESIZE_OFF,
* AUTO_RESIZE_LAST_COLUMN, AUTO_RESIZE_ALL_COLUMNS
*
* @see #getAutoResizeMode()
* @see #sizeColumnsToFit()
* @beaninfo
* description: Whether the columns should adjust themselves automatically to accomodate changes.
* enum: AUTO_RESIZE_OFF JTable.AUTO_RESIZE_OFF
* AUTO_RESIZE_LAST_COLUMN JTable.AUTO_RESIZE_LAST_COLUMN
* AUTO_RESIZE_ALL_COLUMNS JTable.AUTO_RESIZE_ALL_COLUMNS
*/
public void setAutoResizeMode(int mode) {
if ((mode == AUTO_RESIZE_ALL_COLUMNS) ||
(mode == AUTO_RESIZE_LAST_COLUMN) ||
(mode == AUTO_RESIZE_OFF)) {
autoResizeMode = mode;
resizeAndRepaint();
tableHeader.resizeAndRepaint();
}
}
/**
* Returns auto resize mode of the table. The default is
* AUTO_RESIZE_ALL_COLUMNS.
*
* @return the autoResizeMode of the table
*
* @see #setAutoResizeMode()
* @see #sizeColumnsToFit()
*/
public int getAutoResizeMode() {
return autoResizeMode;
}
/**
* Sets the table's autoCreateColumnsFromModel flag. This method
* will call createDefaultColumnsFromModel() if <i>createColumns</i>
* is true.
*
* @param createColumns true if JTable should auto create columns
* @see #getAutoCreateColumnsFromModel()
* @see #createDefaultColumnsFromModel()
* @beaninfo
* description: Automatically populate the columnModel when a new TableModel is submitted.
*/
public void setAutoCreateColumnsFromModel(boolean createColumns) {
if (autoCreateColumnsFromModel != createColumns) {
autoCreateColumnsFromModel = createColumns;
if (autoCreateColumnsFromModel)
createDefaultColumnsFromModel();
}
}
/**
* Returns whether the table will create default columns from the model.
* If this is true, setModel() will clear any existing columns and
* create new columns from the new model. Also if the event in the
* the tableChanged() notification specified the entired table changed
* then the columns will be rebuilt. The default is true.
*
* @return the autoCreateColumnsFromModel of the table
* @see #setAutoCreateColumnsFromModel()
* @see #createDefaultColumnsFromModel()
*/
public boolean getAutoCreateColumnsFromModel() {
return autoCreateColumnsFromModel;
}
/**
* This method will create default columns for the table from
* the data model using the getColumnCount() and getColumnType() methods
* defined in the TableModel interface.
* <p>
* This method will clear any exsiting columns before creating the
* new columns based on information from the model.
*
* @see #getAutoCreateColumnsFromModel()
*/
public void createDefaultColumnsFromModel() {
TableModel m = getModel();
if (m != null) {
// Remove any current columns
TableColumnModel cm = getColumnModel();
cm.removeColumnModelListener(this);
while (cm.getColumnCount() > 0)
cm.removeColumn(cm.getColumn(0));
// Create new columns from the data model info
for (int i = 0; i < m.getColumnCount(); i++) {
TableColumn newColumn = new TableColumn(i);
addColumn(newColumn);
}
cm.addColumnModelListener(this);
}
}
/**
* Set a default renderer to be used if no renderer has been set in
* a TableColumn.
*
* @see #getDefaultRenderer
* @see #setDefaultEditor
*/
public void setDefaultRenderer(Class columnClass, TableCellRenderer renderer) {
defaultRenderersByColumnClass.put(columnClass, renderer);
}
/**
* Returns the renderer to be used when no renderer has been set in
* a TableColumn. During the rendering of cells the renderer is fetched from
* a Hashtable of entries according to the class of the cells in the column. If
* there is no entry for this <I>columnClass</I> the method returns
* the entry for the most specific superclass. The JTable installs entries
* for <I>Object</I>, <I>Number</I> and <I>Boolean</I> all which can be modified
* or replaced.
*
* @see #setDefaultRenderer
* @see #getColumnClass
*/
public TableCellRenderer getDefaultRenderer(Class columnClass) {
if (columnClass == null) {
return null;
}
else {
Object renderer = defaultRenderersByColumnClass.get(columnClass);
if (renderer != null) {
return (TableCellRenderer)renderer;
}
else {
return getDefaultRenderer(columnClass.getSuperclass());
}
}
}
/**
* Set a default editor to be used if no editor has been set in
* a TableColumn. If no editing is required in a table or a
* particular column in a table use the isCellEditable()
* method in the TableModel interface to ensure that the
* JTable will not start an editor in these columns.
*
* @see TableModel#isCellEditable
* @see #getDefaultEditor
* @see #setDefaultRenderer
*/
public void setDefaultEditor(Class columnClass, TableCellEditor editor) {
defaultEditorsByColumnClass.put(columnClass, editor);
}
/**
* Returns the editor to be used when no editor has been set in
* a TableColumn. During the editing of cells the editor is fetched from
* a Hashtable of entries according to the class of the cells in the column. If
* there is no entry for this <I>columnClass</I> the method returns
* the entry for the most specific superclass. The JTable installs entries
* for <I>Object</I>, <I>Number</I> and <I>Boolean</I> all which can be modified
* or replaced.
*
* @see #setDefaultEditor
* @see #getColumnClass
*/
public TableCellEditor getDefaultEditor(Class columnClass) {
if (columnClass == null) {
return null;
}
else {
Object editor = defaultEditorsByColumnClass.get(columnClass);
if (editor != null) {
return (TableCellEditor)editor;
}
else {
return getDefaultEditor(columnClass.getSuperclass());
}
}
}
//
// Selection methods
//
/**
* Sets the table's selection mode to allow only single selections, a single
* contiguous interval, or multiple intervals.
*
* NOTE:<br>
* JTable provides all the methods for handling column and row selection.
* When setting states, such as setSelectionMode, it not only
* updates the mode for the row selection model but also sets similar
* values in the selection model of the columnModel.
* If you want to have states that is different between rows and columns
* you can get the columnModel and change that directly.
* <p>
* Both the row and column selection models for the JTable default
* to using a DefaultListSelectionModel so that JTable works the same
* way as the JList. See setSelectionMode() in JList for details
* about the modes.
*
* @see JList#setSelectionMode
* @beaninfo
* description: The selection mode used by the row and column selection models.
* enum: SINGLE_SELECTION ListSelectionModel.SINGLE_SELECTION
* SINGLE_INTERVAL_SELECTION ListSelectionModel.SINGLE_INTERVAL_SELECTION
* MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
*/
public void setSelectionMode(int selectionMode) {
clearSelection();
getSelectionModel().setSelectionMode(selectionMode);
getColumnModel().getSelectionModel().setSelectionMode(selectionMode);
}
/**
* Sets whether the rows in this model can be selected.
*
* @see #getRowSelectionAllowed()
* @beaninfo
* description: If true, an entire row is selected for each selected cell.
*/
public void setRowSelectionAllowed(boolean flag) {
clearSelection();
rowSelectionAllowed = flag;
}
/**
* Returns true if rows can be selected.
*
* @return true if rows can be selected
* @see #setRowSelectionAllowed()
*/
public boolean getRowSelectionAllowed() {
return rowSelectionAllowed;
}
/**
* Sets whether the columns in this model can be selected.
*
* @see #getColumnSelectionAllowed()
* @beaninfo
* description: If true, an entire column is selected for each selected cell.
*/
public void setColumnSelectionAllowed(boolean flag) {
clearSelection();
columnModel.setColumnSelectionAllowed(flag);
}
/**
* Returns true if columns can be selected.
*
* @return true if columns can be selected.
* @see #setColumnSelectionAllowed
*/
public boolean getColumnSelectionAllowed() {
return columnModel.getColumnSelectionAllowed();
}
/**
* Sets whether this table allows both a column selection and a
* row selection to exist at the same time. When set, this results
* in a facility to select a rectangular region of cells in the display.
* This flag over-rides the row and column selection
* modes ensuring that cell selection is possible whenever this flag is set.
* @see #getCellSelectionEnabled
* @beaninfo
* description: Select a rectangular region of cells rather than rows or columns.
*/
public void setCellSelectionEnabled(boolean flag) {
clearSelection();
cellSelectionEnabled = flag;
}
/**
* Returns true if simultaneous row and column selections are allowed
*
* @return true if simultaneous row and column selections are allowed
* @see #setCellSelectionEnabled
*/
public boolean getCellSelectionEnabled() {
return cellSelectionEnabled;
}
/**
* If a column is selected, then this selects all columns. Similarly,
* if a row is selected, then, this selects all rows. If both a column
* and a row are selected at the time this method is invoked, then
* all columns and rows are selected.
*/
public void selectAll() {
if (getSelectedRowCount() > 0) {
// select all rows
int count = getRowCount();
if (count > 0)
setRowSelectionInterval(0, count);
}
if (getSelectedColumnCount() > 0) {
int count = getColumnCount();
if (count > 0)
setColumnSelectionInterval(0, count);
}
}
/**
* Deselects all selected columns and rows. If empty selection is not
* allowed, then it leaves the first row selected.
*/
public void clearSelection() {
columnModel.getSelectionModel().clearSelection();
selectionModel.clearSelection();
}
/**
* Selects the rows from <i>index0</i> to <i>index1</i> inclusive.
*
* @param index0 one end of the interval.
* @param index1 other end of the interval
*/
public void setRowSelectionInterval(int index0, int index1) {
selectionModel.setSelectionInterval(index0, index1);
}
/**
* Selects the columns from <i>index0</i> to <i>index1</i> inclusive.
*
* @param index0 one end of the interval.
* @param index1 other end of the interval
*/
public void setColumnSelectionInterval(int index0, int index1) {
columnModel.getSelectionModel().setSelectionInterval(index0, index1);
}
/**
* Adds the rows from <i>index0</i> to <i>index0</i> inclusive to
* the current selection.
*
* @param index0 one end of the interval.
* @param index1 other end of the interval
*/
public void addRowSelectionInterval(int index0, int index1) {
selectionModel.addSelectionInterval(index0, index1);
}
/**
* Adds the columns from <i>index0</i> to <i>index0</i> inclusive to
* the current selection.
*
* @param index0 one end of the interval.
* @param index1 other end of the interval
*/
public void addColumnSelectionInterval(int index0, int index1) {
columnModel.getSelectionModel().addSelectionInterval(index0, index1);
}
/**
* Deselects the rows from <i>index0</i> to <i>index0</i> inclusive.
*
* @param index0 one end of the interval.
* @param index1 other end of the interval
*/
public void removeRowSelectionInterval(int index0, int index1) {
selectionModel.removeSelectionInterval(index0, index1);
}
/**
* Deselects the columns from <i>index0</i> to <i>index0</i> inclusive.
*
* @param index0 one end of the interval.
* @param index1 other end of the interval
*/
public void removeColumnSelectionInterval(int index0, int index1) {
columnModel.getSelectionModel().removeSelectionInterval(index0, index1);
}
/**
* Returns the index of the last row selected or added to the selection.
*
* @return the index of the last row selected or added to the selection,
* (lead selection) or -1 if no row is selected.
* @see #getSelectedRows()
*/
public int getSelectedRow() {
if (selectionModel != null) {
return selectionModel.getAnchorSelectionIndex();
}
return -1;
}
/**
* Returns the index of the last column selected or added to the selection.
*
* @return the index of the last column selected or added to the selection,
* (lead selection) or -1 if no column is selected.
* @see #getSelectedColumns()
*/
public int getSelectedColumn() {
return columnModel.getSelectionModel().getAnchorSelectionIndex();
}
/**
* Returns the indices of all selected rows.
*
* @return an array of ints containing the indices of all selected rows,
* or an empty array if no row is selected.
* @see #getSelectedRow()
*/
public int[] getSelectedRows() {
if (selectionModel != null) {
int iMin = selectionModel.getMinSelectionIndex();
int iMax = selectionModel.getMaxSelectionIndex();
if ((iMin == -1) || (iMax == -1)) {
return new int[0];
}
int[] rvTmp = new int[1+ (iMax - iMin)];
int n = 0;
for(int i = iMin; i <= iMax; i++) {
if (selectionModel.isSelectedIndex(i)) {
rvTmp[n++] = i;
}
}
int[] rv = new int[n];
System.arraycopy(rvTmp, 0, rv, 0, n);
return rv;
}
return new int[0];
}
/**
* Returns the indices of all selected columns.
*
* @return an array of ints containing the indices of all selected columns,
* or an empty array if no column is selected.
* @see #getSelectedColumn()
*/
public int[] getSelectedColumns() {
return columnModel.getSelectedColumns();
}
/**
* Returns the number of selected rows.
*
* @return the number of selected rows, 0 if no columns are selected
*/
public int getSelectedRowCount() {
if (selectionModel != null) {
int iMin = selectionModel.getMinSelectionIndex();
int iMax = selectionModel.getMaxSelectionIndex();
int count = 0;
for(int i = iMin; i <= iMax; i++) {
if (selectionModel.isSelectedIndex(i)) {
count++;
}
}
return count;
}
return 0;
}
/**
* Returns the number of selected columns.
*
* @return the number of selected columns, 0 if no columns are selected
*/
public int getSelectedColumnCount() {
return columnModel.getSelectedColumnCount();
}
/**
* Returns true if the row at the specified index is selected
*
* @return true if the row at index <I>row</I> is selected, where 0 is the
* first row
* @exception IllegalArgumentException if <I>row</I> is not in the
* valid range
*/
public boolean isRowSelected(int row) {
if (selectionModel != null)
return selectionModel.isSelectedIndex(row);
return false;
}
/**
* Returns true if the column at the specified index is selected
*
* @return true if the column at index <I>column</I> is selected, where
* 0 is the first column
* @exception IllegalArgumentException if <I>column</I> is not in the
* valid range
*/
public boolean isColumnSelected(int column) {
return columnModel.getSelectionModel().isSelectedIndex(column);
}
/**
* Returns true if the cell at the specified position is selected.
*
* @return true if the cell at index <I>(row, column)</I> is selected,
* where the first row and first column are at index 0
* @exception IllegalArgumentException if <I>row</I> or <I>column</I>
* are not in the valid range
*/
public boolean isCellSelected(int row, int column) {
if (cellSelectionEnabled)
return isRowSelected(row) && isColumnSelected(column);
else
return (getRowSelectionAllowed() && isRowSelected(row)) ||
(getColumnSelectionAllowed() && isColumnSelected(column));
}
/**
* Returns the foreground color for selected cells.
*
* @return the Color object for the foreground property
* @see #setSelectionForeground
* @see #setSelectionBackground
*/
public Color getSelectionForeground() {
return selectionForeground;
}
/**
* Set the foreground color for selected cells. Cell renderers
* can use this color to render text and graphics for selected
* cells.
* <p>
* The default value of this property is defined by the look
* and feel implementation.
* <p>
* This is a JavaBeans bound property.
*
* @param selectionForeground the Color to use in the foreground
* for selected list items
* @see #getSelectionForeground
* @see #setSelectionBackground
* @see #setForeground
* @see #setBackground
* @see #setFont
* @beaninfo
* bound: true
* description: A default foreground color for selected cells.
*/
public void setSelectionForeground(Color selectionForeground) {
Color oldValue = this.selectionForeground;
this.selectionForeground = selectionForeground;
firePropertyChange("selectionForeground", oldValue, selectionForeground);
}
/**
* Returns the background color for selected cells.
*
* @return the Color used for the background of selected list items
* @see #setSelectionBackground
* @see #setSelectionForeground
*/
public Color getSelectionBackground() {
return selectionBackground;
}
/**
* Set the background color for selected cells. Cell renderers
* can use this color to the fill selected cells.
* <p>
* The default value of this property is defined by the look
* and feel implementation.
* <p>
* This is a JavaBeans bound property.
*
* @param selectionBackground the Color to use for the background
* of selected cells
* @see #getSelectionBackground
* @see #setSelectionForeground
* @see #setForeground
* @see #setBackground
* @see #setFont
* @beaninfo
* bound: true
* description: A default background color for selected cells.
*/
public void setSelectionBackground(Color selectionBackground) {
Color oldValue = this.selectionBackground;
this.selectionBackground = selectionBackground;
firePropertyChange("selectionBackground", oldValue, selectionBackground);
}
/**
* Returns the <B>TableColumn</B> object for the column in the table
* whose identifier is equal to <I>identifier</I>, when compared using
* <I>equals()</I>.
*
* @return the TableColumn object with matching identifier
* @exception IllegalArgumentException if <I>identifier</I> is null or no TableColumn has this identifier
*
* @param identifier the identifier object
*/
public TableColumn getColumn(Object identifier) {
TableColumnModel cm = getColumnModel();
int columnIndex = cm.getColumnIndex(identifier);
return cm.getColumn(columnIndex);
}
//
// Informally implement the TableModel interface.
//
/**
* Return the index of the column in the model whose data is being displayed in
* the column <I>viewColumnIndex</I> in the display. Returns <I>viewColumnIndex</I>
* unchanged when <I>viewColumnIndex</I> is less than zero.
*
* @see #convertColumnIndexToView
*/
public int convertColumnIndexToModel(int viewColumnIndex) {
if (viewColumnIndex < 0) {
return viewColumnIndex;
}
return getColumnModel().getColumn(viewColumnIndex).getModelIndex();
}
/**
* Return the index of the column in the view which is displaying the
* data from the column <I>modelColumnIndex</I> in the model. Returns
* -1 if this column is not being displayed. Returns <I>modelColumnIndex</I>
* unchanged when <I>modelColumnIndex</I> is less than zero.
*
* @see #convertColumnIndexToModel
*/
public int convertColumnIndexToView(int modelColumnIndex) {
if (modelColumnIndex < 0) {
return modelColumnIndex;
}
TableColumnModel cm = getColumnModel();
for (int column = 0; column < getColumnCount(); column++) {
if (cm.getColumn(column).getModelIndex() == modelColumnIndex) {
return column;
}
}
return -1;
}
/**
* Returns the number of rows in the table.
*
* @see #getColumnCount()
*/
public int getRowCount() {
return getModel().getRowCount();
}
/**
* Returns the number of columns in the column model, note this may
* be different to the number of columns in the table model.
*
* @return the number of columns in the table
* @see #getRowCount()
*/
public int getColumnCount() {
return getColumnModel().getColumnCount();
}
/**
* Returns the name of the column at the specified view position.
*
* @return the name of the column at position <I>column</I> in the view
* where the first column is column 0.
*/
public String getColumnName(int column) {
return getModel().getColumnName(convertColumnIndexToModel(column));
}
/**
* Returns the type of the column at the specified view position.
*
* @return the type of the column at position <I>column</I> in the view
* where the first column is column 0.
*/
public Class getColumnClass(int column) {
return getModel().getColumnClass(convertColumnIndexToModel(column));
}
/**
* Returns the cell value at <I>row</I> and <I>column</I>.
* <p>
* <b>NOTE</b>: The column is specified in the table view's display
* order, and not in the TableModel's column order. This is
* an important distinction because as the user rearranges
* the columns in the table, what is at column 2 changes.
* Meanwhile the user's actions never affect the model's
* column ordering.
*
* @param row the row whose value is to be looked up
* @param column the column whose value is to be looked up
* @return the Object at the specified cell
*/
public Object getValueAt(int row, int column) {
return getModel().getValueAt(row, convertColumnIndexToModel(column));
}
/**
* Sets the value for the cell at <I>row</I> and <I>column</I>.
* <I>aValue</I> is the new value.
*
* @param aValue the new value
* @param row the row whose value is to be changed
* @param column the column whose value is to be changed
* @see #getValueAt()
*/
public void setValueAt(Object aValue, int row, int column) {
getModel().setValueAt(aValue, row, convertColumnIndexToModel(column));
}
/**
* Returns true if the cell at <I>row</I> and <I>column</I>
* is editable. Otherwise, setValueAt() on the cell will not change
* the value of that cell.
*
* @param row the row whose value is to be looked up
* @param column the column whose value is to be looked up
* @return true if the cell is editable.
* @see #setValueAt()
*/
public boolean isCellEditable(int row, int column) {
return getModel().isCellEditable(row, convertColumnIndexToModel(column));
}
//
// Adding and removing columns in the view
//
/**
* Appends <I>aColumn</I> to the end of the array of columns held by
* the JTable's column model.
* If the header value of <I>aColumn</I> is <I>null</I>,
* sets the header value of <I>aColumn</I> to the name
* returned by <code>getModel().getColumnName()</code>.
* <p>
* To add a column to the JTable to display the <I>modelColumn</I>'th column of
* data in the model, with a given <I>width</I>,
* <I>cellRenderer</I> and <I>cellEditor</I> you can use:
* <pre>
*
* addColumn(new TableColumn(modelColumn, width, cellRenderer, cellEditor));
*
* </pre>
* [All of the other constructors in the TableColumn can be used in place of
* this one.] The model column is stored inside the TableColumn and is used during
* rendering and editing to locate the appropriate data values in the
* model. The model column does not change when columns are reordered
* in the view.
*
* @param aColumn The <B>TableColumn</B> to be added
* @see #removeColumn
*/
public void addColumn(TableColumn aColumn) {
int modelColumn = aColumn.getModelIndex();
String columnName = getModel().getColumnName(modelColumn);
if (aColumn.getHeaderValue() == null) {
aColumn.setHeaderValue(columnName);
}
getColumnModel().addColumn(aColumn);
}
/**
* Removes <I>aColumn</I> from the JTable's array of columns.
* Note: this method does not remove the column of data from the
* model it just removes the TableColumn that was displaying it.
*
* @param aColumn The <B>TableColumn</B> to be removed
* @see #addColumn
*/
public void removeColumn(TableColumn aColumn) {
getColumnModel().removeColumn(aColumn);
}
/**
* Moves the column <I>column</I> to the position currently occupied by the
* column <I>targetColumn</I>. The old column at <I>targetColumn</I> is
* shifted left or right to make room.
*
* @param column the index of column to be moved
* @param targetColumn the new index of the column
*/
public void moveColumn(int column, int targetColumn) {
getColumnModel().moveColumn(column, targetColumn);
}
//
// Cover methods for various models and helper methods
//
/**
* Returns the index of the column that <I>point</I> lies in, or -1 if it
* lies outside the receiver's bounds.
*
* @return the index of the column that <I>point</I> lies in, or -1 if it
* lies outside the receiver's bounds
* @see #rowAtPoint
*/
public int columnAtPoint(Point point) {
return getColumnModel().getColumnIndexAtX(point.x);
}
/**
* Returns the index of the row that <I>point</I> lies in, or -1 if is
* not in the range [0, getRowCount()-1].
*
* @return the index of the row that <I>point</I> lies in, or -1 if it
* is not in the range [0, getRowCount()-1]
* @see #columnAtPoint()
*/
public int rowAtPoint(Point point) {
int y = point.y;
// if (y < 0 || y >= getBounds().height) {
// return -1;
// }
int rowHeight = getRowHeight();
int rowSpacing = getIntercellSpacing().height;
int totalRowHeight = rowHeight + rowSpacing;
int result = y/totalRowHeight;
if (result < 0) {
return -1;
}
else if (result >= getRowCount()) {
return -1;
}
else {
return result;
}
}
/**
* Returns a rectangle locating the cell that lies at the intersection of
* <I>row</I> and <I>column</I>. If <I>includeSpacing</I> is true then
* the value returned includes the intercellSpacing margin. If it is false,
* then the returned rect is inset by half of intercellSpacing.
* (This is the true frame of the cell)
*
* @param row the row to compute
* @param column the column to compute
* @param includeSpacing if true, the rect returned will
* include the correct
* intercellSpacing
* @return the rectangle containing the cell at index
* <I>row</I>,<I>column</I>
* @exception IllegalArgumentException If <I>row</I> or <I>column</I>
* are not in the valid range.
*/
public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
int index = 0;
Rectangle cellFrame;
int columnMargin = getColumnModel().getColumnMargin();
Enumeration enumeration = getColumnModel().getColumns();
TableColumn aColumn;
cellFrame = new Rectangle();
cellFrame.height = getRowHeight() + rowMargin;
cellFrame.y = row * cellFrame.height;
while (enumeration.hasMoreElements()) {
aColumn = (TableColumn)enumeration.nextElement();
cellFrame.width = aColumn.getWidth() + columnMargin;
if (index == column)
break;
cellFrame.x += cellFrame.width;
index++;
}
if (!includeSpacing) {
Dimension spacing = getIntercellSpacing();
// This is not the same as grow(), it rounds differently.
cellFrame.setBounds(cellFrame.x + spacing.width/2,
cellFrame.y + spacing.height/2,
cellFrame.width - spacing.width,
cellFrame.height - spacing.height);
}
return cellFrame;
}
/**
* This method will resize one or more columns of the table
* so that the sum width of all columns will equal to the
* width of the table. If <I>lastColumnOnly</I> is true, then
* it will try to resize the last column only to make it fit,
* but if it runs into either the minimum size limit of the column
* or maximum size limit, then it will change the next to last column also,
* etc. If <I>lastColumnOnly</I> is false, then it will spread the
* size delta proportionately to all the columns, while respecting
* each column's max and min size limits. Also, notifications of each
* column width change will be sent out as they are resized. <p>
*
* Note: It is possible that even after this method is called,
* the total width of the columns is still not be equal to the width
* of the table. eg. A table with a single column, the column has a
* minimum width of 20, and the tableView has a width of 10. And there
* is nothing I can do about that.
*
* @param lastColumnOnly Try to change the last column only if true
* @see TableColumn#setWidth()
*/
public void sizeColumnsToFit(boolean lastColumnOnly) {
int intercellWidth = getColumnModel().getColumnMargin();
int frameWidth = getWidth();
int totalColumnWidth = 0;
TableColumn aColumn;
int index = 0;
int[] columnWidths = new int[this.getColumnCount()];
int[] columnMaxWidths = new int[this.getColumnCount()];
int[] columnMinWidths = new int[this.getColumnCount()];
int maxColumnDelta;
// Fetch all the column width related info and put them in my int arrays
Enumeration enumeration = getColumnModel().getColumns();
while (enumeration.hasMoreElements()) {
aColumn = (TableColumn)enumeration.nextElement();
columnWidths[index] = aColumn.getWidth();
columnMaxWidths[index] = aColumn.getMaxWidth();
columnMinWidths[index] = aColumn.getMinWidth();
totalColumnWidth += aColumn.getWidth() + intercellWidth;
index++;
}
// What's the amount of space we must grow or shrink by
int delta = frameWidth - totalColumnWidth;
if ((-1 <= delta) && (delta <= 1))
return; // Too small to worry about
// Ok, we can now adjust the values in my columnWidths[] array to reflect
// the new desired width.
if (lastColumnOnly) {
// The basic idea if lastColumnOnly is true is we start with
// the last column adjust the width up or down. If we hit
// a max or min limit than we take the reminder and apply that
// to the next to last column. Repeat as needed.
for (index = this.getColumnCount() - 1; index >= 0; index--) {
if (delta > 0) {
// We are growing the column
maxColumnDelta = columnMaxWidths[index] - columnWidths[index];
}
else {
// Shrinking. Note the maxColumnDelta is going to be negative.
maxColumnDelta = columnMinWidths[index] - columnWidths[index];
}
if (Math.abs(maxColumnDelta) >= Math.abs(delta)) {
columnWidths[index] += delta;
break;
}
else {
columnWidths[index] += maxColumnDelta;
delta -= maxColumnDelta;
}
}
}
else {
// We have to spread the delta across all the columns. To do this
// simply and safely, we calculate a percentage value for each
// iteration across all the columns.
float[] percentShare = new float[this.getColumnCount()];
boolean stillHaveRoom = true;
// Lets compute the percentShare of the delta that each column
// should take up, before we change any columns.
// Note: the sum of all the percentages in the array should be 100
for (index = 0; index < this.getColumnCount(); index++) {
percentShare[index] = ((float)(columnWidths[index]+intercellWidth) /
((float)totalColumnWidth));
}
// Now we will iterate 1 or more times to distribute the delta,
// stopping when delta reaches zero. Unless none of the columns
// can change any more because they have all hit their bound limits.
// In which case, we also stop.
while ((delta != 0) && stillHaveRoom) {
int deltaRemainder = delta;
stillHaveRoom = false;
for (index = 0; index < this.getColumnCount(); index++) {
int shareDelta = (int)Math.ceil((float)delta * percentShare[index]);
// Have to check if deltaRemainder is zero here, if it
// is then we break. This is needed because we are
// computing the shareDelta using ints which can lead
// to some funny cases with small deltas. eg. a table
// with 6 equal sized columns, and the delta is 2.
// Leading to each column's share being 0.33. If I round
// down then every column's shareDelta is 0, and the
// loop will never end. So what I have choose to do
// is take the ceiling. In the example above, then
// the first column gets 1, and the second also gets
// 1, bring the deltaRemainder to 0, and we should
// stop.
if (deltaRemainder == 0) {
break;
}
else if (Math.abs(deltaRemainder) < Math.abs(shareDelta)) {
// Here we are making sure we don't go over our
// delta because of the ceiling. eg. we have a delta
// of 27. The 3 column's share computes to 10.2, 10.2,
// and 6.6. When rounded up becomes 11, 11, 7, which
// adds up to 29. This check will make the last column's
// share equal to 5.
shareDelta = deltaRemainder;
}
if (shareDelta > 0) {
// We are growing the column
maxColumnDelta = columnMaxWidths[index] - columnWidths[index];
}
else if (shareDelta < 0) {
// Shrinking. Note the maxColumnDelta is going to be negative.
maxColumnDelta = columnMinWidths[index] - columnWidths[index];
}
else {
// My share is zero, so do nothing.
continue;
}
if (Math.abs(maxColumnDelta) >= Math.abs(shareDelta)) {
stillHaveRoom = true;
columnWidths[index] += shareDelta;
deltaRemainder -= shareDelta;
}
else if (maxColumnDelta != 0) {
columnWidths[index] += maxColumnDelta;
deltaRemainder -= maxColumnDelta;
// I've hit my limits, so I'm going to mark this
// by changing my percentShare to zero
percentShare[index] = 0;
}
}
// Update local vars for next loop iteration
delta = deltaRemainder; // It is important that delta not
// change in the for loop above
if (delta != 0) {
// We have to loop again because one or more columns
// couldn't take their full share of the delta. And because
// those columns can't take any more in the next iteration,
// their percentShare number has been set to zero. Now the
// sum total of all the percentShares is less than 100%.
// So we are going to adjust the percent shares so their sum
// total is once again 100%. Otherwise, the loop will take
// a long time to end, and we'll just get closer and closer
// in many iterations before reaching some where near zero.
float adjustment, percentLeft = 0;
for (index = 0; index < this.getColumnCount(); index++) {
percentLeft += percentShare[index];
}
adjustment = 100 / percentLeft;
for (index = 0; index < this.getColumnCount(); index++) {
percentShare[index] *= adjustment;
}
}
}
}
// Now we really set the widths based on the final value of the array
index = 0;
enumeration = getColumnModel().getColumns();
while (enumeration.hasMoreElements()) {
aColumn = (TableColumn)enumeration.nextElement();
aColumn.setWidth(columnWidths[index]);
index++;
}
}
/**
* Overrides JComponent's setToolTipText method to allow use of the
* renderer's tips (if the renderer has text set).
* <p>
* NOTE: For JTable to properly display tooltips of its renderers
* JTable must be a registered component with the ToolTipManager.
* This is done automatically in initializeLocalVars(), but
* if at a later point JTable is told setToolTipText(null)
* it will unregister the table component, and no tips from
* renderers will display anymore.
*
* @see JComponent#getToolTipText
*/
public String getToolTipText(MouseEvent event) {
String tip = null;
Point p = event.getPoint();
// Locate the renderer under the event location
int hitColumnIndex = columnAtPoint(p);
int hitRowIndex = rowAtPoint(p);
if ((hitColumnIndex != -1) && (hitRowIndex != -1)) {
TableColumn aColumn = getColumnModel().getColumn(hitColumnIndex);
TableCellRenderer renderer = aColumn.getCellRenderer();
if (renderer == null) {
Class columnClass = getColumnClass(hitColumnIndex);
renderer = getDefaultRenderer(columnClass);
}
Component component = renderer.getTableCellRendererComponent(
this, null, false, false,
hitRowIndex, hitColumnIndex);
// Now have to see if the component is a JComponent before
// getting the tip
if (component instanceof JComponent) {
// Convert the event to the renderer's coordinate system
MouseEvent newEvent;
Rectangle cellRect = getCellRect(hitRowIndex, hitColumnIndex, false);
p.translate(-cellRect.x, -cellRect.y);
newEvent = new MouseEvent(component, event.getID(),
event.getWhen(), event.getModifiers(),
p.x, p.y, event.getClickCount(),
event.isPopupTrigger());
tip = ((JComponent)component).getToolTipText(newEvent);
}
}
// No tip from the renderer get our own tip
if (tip == null)
tip = getToolTipText();
return tip;
}
//
// Editing Support
//
/**
* Programmatically starts editing the cell at <I>row</I> and
* <I>column</I>, if the cell is editable.
*
* @param row the row to be edited
* @param column the column to be edited
* @exception IllegalArgumentException If <I>row</I> or <I>column</I>
* are not in the valid range
* @return false if for any reason the cell cannot be edited.
*/
public boolean editCellAt(int row, int column) {
return editCellAt(row, column, null);
}
/**
* Programmatically starts editing the cell at <I>row</I> and
* <I>column</I>, if the cell is editable.
* To prevent the JTable from editing a particular table, column or
* cell value, return false from the isCellEditable() method in the
* TableModel interface.
*
* @param row the row to be edited
* @param column the column to be edited
* @param e event to pass into
* shouldSelectCell
* @exception IllegalArgumentException If <I>row</I> or <I>column</I>
* are not in the valid range
* @return false if for any reason the cell cannot be edited.
*/
public boolean editCellAt(int row, int column, EventObject e){
if (!isCellEditable(row, column))
return false;
if (isEditing()) {
// Try to stop the current editor
if (cellEditor != null) {
boolean stopped = cellEditor.stopCellEditing();
if (!stopped)
return false; // The current editor not resigning
}
}
TableColumn tableColumn = getColumnModel().getColumn(column);
TableCellEditor editor = tableColumn.getCellEditor();
if (editor == null) {
editor = getDefaultEditor(getColumnClass(column));
}
if (editor != null) {
// prepare editor - size it then added it to the table
editorComp = prepareEditor(editor, row, column);
if (editor.isCellEditable(e)) {
editorComp.setBounds(getCellRect(row, column, false));// PENDING(philip)
this.add(editorComp);
editorComp.validate();
// PENDING: this could convert event at this point!
boolean shouldSelect = editor.shouldSelectCell(e);
setCellEditor(editor);
setEditingRow(row);
setEditingColumn(column);
editor.addCellEditorListener(this);
repaint();
return true;
}
}
return false;
}
/**
* Returns true is the table is editing a cell.
*
* @return true is the table is editing a cell
* @see #editingColumn()
* @see #editingRow()
*/
public boolean isEditing() {
return (cellEditor == null)? false : true;
}
/**
* If the receiver is currently editing this will return the Component
* that was returned from the CellEditor.
*
* @return Component handling editing session
*/
public Component getEditorComponent() {
return editorComp;
}
/**
* This returns the index of the editing column.
*
* @return the index of the column being edited
* @see #editingRow()
*/
public int getEditingColumn() {
return editingColumn;
}
/**
* Returns the index of the editing row.
*
* @return the index of the row being edited
* @see #editingColumn()
*/
public int getEditingRow() {
return editingRow;
}
//
// Managing TableUI
//
/**
* Returns the L&F object that renders this component.
*
* @return the TableUI object that renders this component
*/
public TableUI getUI() {
return (TableUI)ui;
}
/**
* Sets the L&F object that renders this component.
*
* @param ui the TableUI L&F object
* @see UIDefaults#getUI
*/
public void setUI(TableUI ui) {
if (this.ui != ui) {
super.setUI(ui);
repaint();
}
}
private void updateSubComponentUI(Object componentShell) {
if (componentShell == null) {
return;
}
Component component = null;
if (componentShell instanceof Component) {
component = (Component)componentShell;
}
if (componentShell instanceof DefaultCellEditor) {
component = ((DefaultCellEditor)componentShell).getComponent();
}
if (component != null && component instanceof JComponent) {
((JComponent)component).updateUI();
}
}
/**
* Notification from the UIManager that the L&F has changed.
* Replaces the current UI object with the latest version from the
* UIManager.
*
* @see JComponent#updateUI
*/
public void updateUI() {
// Update the UIs of the cell renderers, cell editors and header renderers.
TableColumnModel cm = getColumnModel();
for(int column = 0; column < cm.getColumnCount(); column++) {
TableColumn aColumn = cm.getColumn(column);
// updateSubComponentUI(aColumn.getCellRenderer());
updateSubComponentUI(aColumn.getCellEditor());
// updateSubComponentUI(aColumn.getHeaderRenderer());
}
// Update the UIs of all the default renderers.
/*
Enumeration defaultRenderers = defaultRenderersByColumnClass.elements();
while (defaultRenderers.hasMoreElements()) {
updateSubComponentUI(defaultRenderers.nextElement());
}
*/
// Update the UIs of all the default editors.
Enumeration defaultEditors = defaultEditorsByColumnClass.elements();
while (defaultEditors.hasMoreElements()) {
updateSubComponentUI(defaultEditors.nextElement());
}
setUI((TableUI)UIManager.getUI(this));
resizeAndRepaint();
invalidate();//PENDING
}
/**
* Returns the name of the L&F class that renders this component.
*
* @return "TableUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return "TableUI";
}
//
// Managing models
//
/**
* Sets the data model for this table to <I>newModel</I> and registers
* with for listner notifications from the new data model.
*
* @param newModel the new data source for this table
* @exception IllegalArgumentException if <I>newModel</I> is null
* @see #getModel()
* @beaninfo
* description: The model that is the source of the data for this view.
*/
public void setModel(TableModel newModel) {
TableModel oldModel = dataModel;
if (newModel == null)
throw new IllegalArgumentException("Cannot set a null TableModel");
if (newModel != oldModel) {
if (oldModel != null)
oldModel.removeTableModelListener(this);
dataModel = newModel;
newModel.addTableModelListener(this);
// If this method is called from the JTable constructor,
// the column model will be null. In this case we can't use
// the usual methods to update the internal state. In all other
// cases, use the usual tableChanged() method to reconfigure
// the JTable for the new model.
if (getColumnModel() != null) {
tableChanged(new TableModelEvent(dataModel, TableModelEvent.HEADER_ROW));
}
}
}
/**
* Returns the <B>TableModel</B> that provides the data displayed by
* the receiver.
*
* @return the object that provides the data displayed by the receiver
* @see #setModel()
*/
public TableModel getModel() {
return dataModel;
}
/**
* Sets the column model for this table to <I>newModel</I> and registers
* with for listner notifications from the new column model. Also sets
* the column model of the JTableHeader to <I>newModel</I>.
*
* @param newModel the new data source for this table
* @exception IllegalArgumentException if <I>newModel</I> is null
* @see #getColumnModel()
* @beaninfo
* description: The object governing the way columns appear in the view.
*/
public void setColumnModel(TableColumnModel newModel) {
if (newModel == null) {
throw new IllegalArgumentException("Cannot set a null ColumnModel");
}
TableColumnModel oldModel = columnModel;
if (newModel != oldModel) {
if (oldModel != null)
oldModel.removeColumnModelListener(this);
columnModel = newModel;
newModel.addColumnModelListener(this);
// Set the column model of the header as well.
if (tableHeader != null) {
tableHeader.setColumnModel(newModel);
}
resizeAndRepaint();
}
}
/**
* Returns the <B>TableColumnModel</B> that contains all column inforamtion
* of this table.
*
* @return the object that provides the column state of the table
* @see #setColumnModel()
*/
public TableColumnModel getColumnModel() {
return columnModel;
}
/**
* Sets the row selection model for this table to <I>newModel</I>
* and registers with for listner notifications from the new selection model.
*
* @param newModel the new selection model
* @exception IllegalArgumentException if <I>newModel</I> is null
* @see #getSelectionModel()
* @beaninfo
* description: The selection model for rows.
*/
public void setSelectionModel(ListSelectionModel newModel) {
if (newModel == null) {
throw new IllegalArgumentException("Cannot set a null SelectionModel");
}
ListSelectionModel oldModel = selectionModel;
if (newModel != oldModel) {
if (oldModel != null) {
oldModel.removeListSelectionListener(this);
}
selectionModel = newModel;
if (newModel != null) {
newModel.addListSelectionListener(this);
}
repaint();
}
}
/**
* Returns the <B>ListSelectionModel</B> that is used to maintain row
* selection state.
*
* @return the object that provides row selection state. Or <B>null</B>
* if row selection is not allowed.
* @see #setSelectionModel()
*/
public ListSelectionModel getSelectionModel() {
return selectionModel;
}
//
// Implementing TableModelListener interface
//
/**
* The TableModelEvent should be constructed in the co-ordinate system
* of the model, the appropriate mapping to the view co-ordinate system
* is performed by the JTable when it recieves the event.
*/
public void tableChanged(TableModelEvent e) {
if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
// The whole thing changed
clearSelection();
if (getAutoCreateColumnsFromModel())
createDefaultColumnsFromModel();
resizeAndRepaint();
if (tableHeader != null) {
tableHeader.resizeAndRepaint();
}
return;
}
if (e.getType() == TableModelEvent.INSERT) {
tableRowsInserted(e);
return;
}
if (e.getType() == TableModelEvent.DELETE) {
tableRowsDeleted(e);
return;
}
int modelColumn = e.getColumn();
int start = e.getFirstRow();
int end = e.getLastRow();
if (start == TableModelEvent.HEADER_ROW) {
start = 0;
end = Integer.MAX_VALUE;
}
int rowHeight = getRowHeight() + rowMargin;
Rectangle dirtyRegion;
if (modelColumn == TableModelEvent.ALL_COLUMNS) {
// 1 or more rows changed
dirtyRegion = new Rectangle(0, start * rowHeight,
getColumnModel().getTotalColumnWidth(), 0);
}
else {
// A cell or column of cells has changed.
// Unlike the rest of the methods in the JTable, the TableModelEvent
// uses the co-ordinate system of the model instead of the view.
// This is the only place in the JTable where this "reverse mapping"
// is used.
int column = convertColumnIndexToView(modelColumn);
dirtyRegion = getCellRect(start, column, false);
}
// Now adjust the height of the dirty region according to the value of "end".
// Check for Integer.MAX_VALUE as this will cause an overflow.
if (end != Integer.MAX_VALUE) {
dirtyRegion.height = (end-start+1)*rowHeight;
repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
}
// In fact, if the end is Integer.MAX_VALUE we need to revalidate anyway
// because the scrollbar may need repainting.
else {
resizeAndRepaint();
}
}
/*
* Invoked when rows have been inserted into the table.
*
* @param e the TableModelEvent encapsulating the insertion
*/
private void tableRowsInserted(TableModelEvent e) {
int start = e.getFirstRow();
if (start < 0)
start = 0;
// 1 or more rows added, so I have to repaint from the first
// new row to the end of the table. (Everything shifts down)
int rowHeight = getRowHeight() + rowMargin;
Rectangle drawRect = new Rectangle(0, start * rowHeight,
getColumnModel().getTotalColumnWidth(),
(getRowCount()-start) * rowHeight);
// Adjust the selection to account for the new rows
if (selectionModel != null) {
int end = e.getLastRow();
if (end < 0)
end = getRowCount()-1;
int length = end - start + 1;
selectionModel.insertIndexInterval(start, length, true);
}
revalidate();
repaint(drawRect.x, drawRect.y, drawRect.width, drawRect.height);
}
/*
* Invoked when rows have been removed from the table.
*
* @param e the TableModelEvent encapsulating the deletion
*/
private void tableRowsDeleted(TableModelEvent e) {
int start = e.getFirstRow();
if (start < 0)
start = 0;
// 1 or more rows added, so I have to repaint from the first
// new row to the end of the table. (Everything shifts down)
int rowHeight = getRowHeight() + rowMargin;
Rectangle drawRect = new Rectangle(0, start * rowHeight,
getColumnModel().getTotalColumnWidth(),
(getRowCount()-start) * rowHeight);
// Adjust the selection to account for the new rows
if (selectionModel != null) {
int end = e.getLastRow();
if (end < 0)
end = getRowCount()-1;
selectionModel.removeIndexInterval(start, end);
}
revalidate();
repaint(drawRect.x, drawRect.y, drawRect.width, drawRect.height);
}
//
// Implementing TableColumnModelListener interface
//
/**
* Tells listeners that a column was added to the model.
*
* @see TableColumnModelListener
*/
public void columnAdded(TableColumnModelEvent e) {
// If I'm currently editing, then I should stop editing
if (isEditing()) {
removeEditor();
}
resizeAndRepaint();
}
/**
* Tells listeners that a column was removed from the model.
*
* @see TableColumnModelListener
*/
public void columnRemoved(TableColumnModelEvent e) {
// If I'm currently editing, then I should stop editing
if (isEditing()) {
removeEditor();
}
resizeAndRepaint();
}
/**
* Tells listeners that a column was repositioned.
*
* @see TableColumnModelListener
*/
public void columnMoved(TableColumnModelEvent e) {
// If I'm currently editing, then I should stop editing
if (isEditing()) {
removeEditor();
}
repaint();
}
/**
* Tells listeners that a column was moved due to a margin change.
*
* @see TableColumnModelListener
*/
public void columnMarginChanged(ChangeEvent e) {
// If I'm currently editing, then I should stop editing
if (isEditing()) {
removeEditor();
}
resizeAndRepaint();
}
/**
* Tells listeners that the selection model of the
* TableColumnModel changed.
*
* @see TableColumnModelListener
*/
public void columnSelectionChanged(ListSelectionEvent e) {
int firstIndex = e.getFirstIndex();
int lastIndex = e.getLastIndex();
if (firstIndex == -1 && lastIndex == -1) { // Selection cleared.
repaint();
}
Rectangle firstColumnRect = getCellRect(0, firstIndex, false);
Rectangle lastColumnRect = getCellRect(getRowCount(), lastIndex, false);
Rectangle dirtyRegion = firstColumnRect.union(lastColumnRect);
// This marks this entire column as dirty but the painting system will
// intersect this with the clip rect of the viewport and redraw only
// the visible cells.
repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
}
//
// Implementing ListSelectionListener interface
//
/**
* Tells listeners that the selection changed.
*
* @see ListSelectionListener
*/
public void valueChanged(ListSelectionEvent e) {
int firstIndex = e.getFirstIndex();
int lastIndex = e.getLastIndex();
if (firstIndex == -1 && lastIndex == -1) { // Selection cleared.
repaint();
}
Rectangle firstRowRect = getCellRect(firstIndex, 0, false);
Rectangle lastRowRect = getCellRect(lastIndex, getColumnCount(), false);
Rectangle dirtyRegion = firstRowRect.union(lastRowRect);
// This marks this entire row as dirty but the painting system will
// intersect this with the clip rect of the viewport and redraw only
// the visible cells.
repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
}
//
// Implementing the CellEditorListener interface
//
/**
* Invoked when editing is finished. The changes are saved, the
* editor object is discarded, and the cell is rendered once again.
*
* @see CellEditorListener
*/
public void editingStopped(ChangeEvent e) {
// Take in the new value
TableCellEditor editor = getCellEditor();
if (editor != null) {
Object value = editor.getCellEditorValue();
setValueAt(value, editingRow, editingColumn);
removeEditor();
}
}
/**
* Invoked when editing is canceled. The editor object is discarded
* and the cell is rendered once again.
*
* @see CellEditorListener
*/
public void editingCanceled(ChangeEvent e) {
removeEditor();
}
//
// Implementing the Scrollable interface
//
/**
* Sets the preferred size of the viewport for this table.
*
* @param size a Dimension object specifying the preferredSize of a
* JViewport whose view is this table
* @see Scrollable#getPreferredScrollableViewportSize
* @beaninfo
* description: The preferred size of the viewport.
*/
public void setPreferredScrollableViewportSize(Dimension size) {
preferredViewportSize = size;
}
/**
* Returns the preferred size of the viewport for this table.
*
* @return a Dimension object containing the preferredSize of the JViewport
* which displays this table
* @see Scrollable#getPreferredScrollableViewportSize
*/
public Dimension getPreferredScrollableViewportSize() {
return preferredViewportSize;
}
/**
* Returns the scroll increment that completely exposes one new row
* or column (depending on the orientation).
* <p>
* This method is called each time the user requests a unit scroll.
*
* @param visibleRect The view area visible within the viewport
* @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
* @param direction Less than zero to scroll up/left, greater than zero for down/right.
* @return The "unit" increment for scrolling in the specified direction
* @see Scrollable#getScrollableUnitIncrement
*/
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
int direction) {
// PENDING(alan): do something smarter
if (orientation == SwingConstants.HORIZONTAL) {
return 1;
}
return rowHeight;
}
/**
* Returns The visibleRect.height or visibleRect.width, depending on the
* table's orientation.
*
* @return The visibleRect.height or visibleRect.width per the orientation.
* @see Scrollable#getScrollableBlockIncrement
*/
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation,
int direction) {
return (orientation == SwingConstants.VERTICAL) ? visibleRect.height :
visibleRect.width;
}
/**
* Returns false to indicate that the width of the viewport does not
* determine the width of the table.
*
* @return false
* @see Scrollable#getScrollableTracksViewportWidth
*/
public boolean getScrollableTracksViewportWidth() {
return false;
}
/**
* Returns false to indicate that the height of the viewport does not
* determine the height of the table.
*
* @return false
* @see Scrollable#getScrollableTracksViewportHeight
*/
public boolean getScrollableTracksViewportHeight() {
return false;
}
//
// Protected Methods
//
private class CheckBoxRenderer extends JCheckBox implements TableCellRenderer
{
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
setSelected((value != null && ((Boolean)value).booleanValue()));
return this;
}
}
protected void createDefaultRenderers() {
defaultRenderersByColumnClass = new Hashtable();
// Objects
DefaultTableCellRenderer label = new DefaultTableCellRenderer();
setDefaultRenderer(Object.class, label);
// Numbers
DefaultTableCellRenderer rightAlignedLabel = new DefaultTableCellRenderer();
rightAlignedLabel.setHorizontalAlignment(JLabel.RIGHT);
setDefaultRenderer(Number.class, rightAlignedLabel);
// Icons
DefaultTableCellRenderer centeredLabel = new DefaultTableCellRenderer() {
public void setValue(Object value) { setIcon((Icon)value); }
};
centeredLabel.setHorizontalAlignment(JLabel.CENTER);
setDefaultRenderer(ImageIcon.class, centeredLabel);
// Booleans
/* DefaultTableCellRenderer booleanRenderer = new DefaultTableCellRenderer() {
Icon trueIcon = UIManager.getIcon("CheckBox.icon");
public void setValue(Object value) {
setIcon((value != null && ((Boolean)value).booleanValue()) ? trueIcon : null);
}
};
booleanRenderer.setHorizontalAlignment(JLabel.CENTER);
setDefaultRenderer(Boolean.class, booleanRenderer);
*/
CheckBoxRenderer booleanRenderer = new CheckBoxRenderer();
booleanRenderer.setHorizontalAlignment(JLabel.CENTER);
setDefaultRenderer(Boolean.class, booleanRenderer);
}
/**
* Creates default cell editors for Objects, numbers, and boolean values.
*/
protected void createDefaultEditors() {
defaultEditorsByColumnClass = new Hashtable();
// Objects
JTextField textField = new JTextField();
textField.setBorder(new LineBorder(Color.black));
setDefaultEditor(Object.class, new DefaultCellEditor(textField));
// Numbers
JTextField rightAlignedTextField = new JTextField();
rightAlignedTextField.setHorizontalAlignment(JTextField.RIGHT);
rightAlignedTextField.setBorder(new LineBorder(Color.black));
setDefaultEditor(Number.class, new DefaultCellEditor(rightAlignedTextField));
// Booleans
JCheckBox centeredCheckBox = new JCheckBox();
centeredCheckBox.setHorizontalAlignment(JCheckBox.CENTER);
setDefaultEditor(Boolean.class, new DefaultCellEditor(centeredCheckBox));
}
/**
* Initializes table properties to their default values.
*/
protected void initializeLocalVars() {
createDefaultRenderers();
createDefaultEditors();
setTableHeader(createDefaultTableHeader());
setShowGrid(true);
setAutoResizeMode(AUTO_RESIZE_ALL_COLUMNS);
setRowHeight(16);
rowMargin = 1;
setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
setColumnSelectionAllowed(false);
setRowSelectionAllowed(true);
setCellSelectionEnabled(false);
cellEditor = null;
editingColumn = editingRow = -1;
preferredViewportSize = new Dimension(450,400);
// I'm registered to do tool tips so we can draw tips for the renderers
ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
toolTipManager.registerComponent(this);
setAutoscrolls(true);
tableHeader.setAutoscrolls(true);
}
/**
* Returns the default table model object which is
* a DefaultTableModel. Subclass can override this
* method to return a different table model object.
*
* @return the default table model object
*/
protected TableModel createDefaultDataModel() {
return new DefaultTableModel();
}
/**
* Returns the default column model object which is
* a DefaultTableColumnModel. Subclass can override this
* method to return a different column model object
*
* @return the default column model object
*/
protected TableColumnModel createDefaultColumnModel() {
return new DefaultTableColumnModel();
}
/**
* Returns the default selection model object which is
* a DefaultListSelectionModel. Subclass can override this
* method to return a different selection model object.
*
* @return the default selection model object
*/
protected ListSelectionModel createDefaultSelectionModel() {
DefaultListSelectionModel m = new DefaultListSelectionModel();
// By turning this off we get notified of the minimal range of rows
// that need to be drawn when the selection changes. This improves
// redrawing performance considerably during mouseDragged.
m.setLeadAnchorNotificationEnabled(false);
return m;
}
/**
* Returns the default table header object which is
* a JTableHeader. Subclass can override this
* method to return a different table header object
*
* @return the default table header object
*/
protected JTableHeader createDefaultTableHeader() {
return new JTableHeader(columnModel);
}
/**
* Properly sizes the receiver and its header view, and marks it as
* needing display. Also resets cursor rectangles for the header view
* and line scroll amounts for the <B>JScrollPane</B>.
*/
protected void resizeAndRepaint() {
revalidate();
repaint();
}
/**
* Return the cellEditor.
*
* @return the TableCellEditor that does the editing
* @see #cellEditor
*/
public TableCellEditor getCellEditor() {
return cellEditor;
}
/**
* Set the cellEditor variable.
*
* @param anEditor the TableCellEditor that does the editing
* @see #cellEditor
*/
public void setCellEditor(TableCellEditor anEditor) {
cellEditor = anEditor;
}
/**
* Set the editingColumn variable.
*
* @see #editingColumn
*/
public void setEditingColumn(int aColumn) {
editingColumn = aColumn;
}
/**
* Set the editingRow variable.
*
* @see #editingRow
*/
public void setEditingRow(int aRow) {
editingRow = aRow;
}
/**
* Returns true to indicate that this component paints every pixel
* in its range. (In other words, it does not have a transparent
* background or foreground.)
*
* @return true
* @see JComponent#isOpaque
*/
public boolean isOpaque() {
return true;
}
/**
* Sets up the specified editor using the value at the specified cell.
*
* @param editor the TableCellEditor to set up
* @param row the row of the cell to edit, where 0 is the first
* @param column the column of the cell to edit, where 0 is the first
*/
public Component prepareEditor(TableCellEditor editor,
int row, int column) {
Object value = getValueAt(row, column);
TableColumn tableColumn = getColumnModel().getColumn(column);
boolean isSelected = isCellSelected(row, column);
Component comp = editor.getTableCellEditorComponent(this, value, isSelected,
row, column);
if((comp != null) && (comp.getFont() == null)) {
comp.setFont(getFont());
}
return comp;
}
/**
* Discard the editor object and return the real estate it used to
* cell rendering.
*/
public void removeEditor() {
TableCellEditor editor = getCellEditor();
if(editor != null) {
editor.removeCellEditorListener(this);
// PENDING(alan): This is a temp work around for a JComboBox bug
if (editorComp instanceof JComboBox) {
((JComboBox)editorComp).hidePopup();
}
remove(editorComp);
Rectangle cellRect = getCellRect(editingRow, editingColumn, false);
repaint(cellRect.x, cellRect.y,
cellRect.width, cellRect.height);
if (!(editorComp instanceof JComponent) ||
((JComponent)editorComp).hasFocus()) {
requestFocus();
}
setCellEditor(null);
setEditingColumn(-1);
setEditingRow(-1);
editorComp = null;
}
}
//
// Serialization
//
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
}
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{
s.defaultReadObject();
createDefaultRenderers();
createDefaultEditors();
}
/////////////////
// Accessibility support
////////////////
/**
* Get the AccessibleContext associated with this JComponent
*
* @return the AccessibleContext of this JComponent
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJTable();
}
return accessibleContext;
}
//
// *** should also implement AccessibleSelction?
// *** and what's up with keyboard navigation/manipulation?
//
/**
* The class used to obtain the accessible role for this object.
* <p>
* Warning: serialized objects of this class will not be compatible with
* future swing releases. The current serialization support is appropriate
* for short term storage or RMI between Swing1.0 applications. It will
* not be possible to load serialized Swing1.0 objects with future releases
* of Swing. The JDK1.2 release of Swing will be the compatibility
* baseline for the serialized form of Swing objects.
*/
protected class AccessibleJTable extends AccessibleJComponent {
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
* @see AccessibleRole
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.TABLE;
}
/**
* Returns the Accessible child, if one exists, contained at the local
* coordinate Point.
*
* @param p The point defining the top-left corner of the Accessible,
* given in the coordinate space of the object's parent.
* @return the Accessible, if it exists, at the specified location;
* else null
*/
public Accessible getAccessibleAt(Point p) {
int column = columnAtPoint(p);
int row = rowAtPoint(p);
if ((column != -1) && (row != -1)) {
TableColumn aColumn = getColumnModel().getColumn(column);
TableCellRenderer renderer = aColumn.getCellRenderer();
if (renderer == null) {
Class columnClass = getColumnClass(column);
renderer = getDefaultRenderer(columnClass);
}
Component component = renderer.getTableCellRendererComponent(
JTable.this, null, false, false,
row, column);
return new AccessibleJTableCell(JTable.this, row, column,
getAccessibleIndexAt(row, column));
}
return null;
}
/**
* Returns the number of accessible children in the object. If all
* of the children of this object implement Accessible, than this
* method should return the number of children of this object.
*
* @return the number of accessible children in the object.
*/
public int getAccessibleChildrenCount() {
return (JTable.this.getColumnCount() * JTable.this.getRowCount());
}
/**
* Return the nth Accessible child of the object.
*
* @param i zero-based index of child
* @return the nth Accessible child of the object
*/
public Accessible getAccessibleChild(int i) {
if (i < 0 || i >= getAccessibleChildrenCount()) {
return null;
} else {
// children increase across, and then down, for tables
// (arbitrary decision)
int column = getAccessibleColumnAtIndex(i);
int row = getAccessibleRowAtIndex(i);
TableColumn aColumn = getColumnModel().getColumn(column);
TableCellRenderer renderer = aColumn.getCellRenderer();
if (renderer == null) {
Class columnClass = getColumnClass(column);
renderer = getDefaultRenderer(columnClass);
}
Component component = renderer.getTableCellRendererComponent(
JTable.this, null, false, false,
row, column);
return new AccessibleJTableCell(JTable.this, row, column,
getAccessibleIndexAt(row, column));
}
}
// /**
// * Get the AccessibleTable associated with this object if one
// * exists. Otherwise return null.
// */
// public AccessibleTable getAccessibleTable() {
// return this;
// }
// AccessibleTable methods
/*
* Returns the total number of rows in the table
*
* @return the total number of rows in the table
*/
private int getAccessibleRowCount() {
return JTable.this.getRowCount();
}
/*
* Returns the total number of columns in the table
*
* @return the total number of columns in the table
*/
private int getAccessibleColumnCount() {
return JTable.this.getColumnCount();
}
/*
* Returns the row at a given index into the table
*
* @param i zero-based index into the table
* @return the row at a given index
*/
private int getAccessibleRowAtIndex(int i) {
return (i / getAccessibleColumnCount());
}
/*
* Returns the column at a given index into the table
*
* @param i zero-based index into the table
* @return the column at a given index
*/
private int getAccessibleColumnAtIndex(int i) {
return (i % getAccessibleColumnCount());
}
/*
* Returns the index at a given (row, column) in the table
*
* @param r zero-based row of the table
* @param c zero-based column of the table
* @return the index into the table
*/
private int getAccessibleIndexAt(int r, int c) {
return ((r * getAccessibleColumnCount()) + c);
}
/*
* Returns the Accessible at a given (row, column) in the table
*
* @param r zero-based row of the table
* @param c zero-based column of the table
* @return the Accessible at the specified (row, column)
*/
private Accessible getAccessibleAt(int r, int c) {
return getAccessibleChild((r * getAccessibleColumnCount()) + c);
}
/*
* Return the Accessible representing the row header, if
* there is one (may be null).
*
* @param row zero-based row of the table
* @return the Accessible header of the row
*/
private Accessible getAccessibleRowHeader(int row) {
return null;
}
/*
* Return the Accessible representing the column header, if
* there is one (may be null)
*
* @param column zero-based column of the table
* @return the Accessible header of the column
*/
private Accessible getAccessibleColumnHeader(int column) {
JTableHeader header = JTable.this.getTableHeader();
AccessibleContext ac = header.getAccessibleContext();
if (ac != null) {
return ac.getAccessibleChild(column);
} else {
return null;
}
}
/**
* The class used to obtain the AccessibleRole for a cell.
*/
protected class AccessibleJTableCell extends AccessibleContext
implements Accessible, AccessibleComponent {
private JTable parent;
private int row;
private int column;
private int index;
/**
* Constructs an AccessiblJTableHeaaderEntry
*/
public AccessibleJTableCell(JTable t, int r, int c, int i) {
parent = t;
row = r;
column = c;
index = i;
this.setAccessibleParent(parent);
}
/**
* Get the AccessibleContext associated with this
*
* @return the AccessibleContext of this JComponent
*/
public AccessibleContext getAccessibleContext() {
return this;
}
private AccessibleContext getCurrentAccessibleContext() {
TableColumn aColumn = getColumnModel().getColumn(column);
TableCellRenderer renderer = aColumn.getCellRenderer();
if (renderer == null) {
Class columnClass = getColumnClass(column);
renderer = getDefaultRenderer(columnClass);
}
Component component = renderer.getTableCellRendererComponent(
JTable.this, null, false, false,
row, column);
if (component instanceof Accessible) {
return ((Accessible) component).getAccessibleContext();
} else {
return null;
}
}
private Component getCurrentComponent() {
TableColumn aColumn = getColumnModel().getColumn(column);
TableCellRenderer renderer = aColumn.getCellRenderer();
if (renderer == null) {
Class columnClass = getColumnClass(column);
renderer = getDefaultRenderer(columnClass);
}
return renderer.getTableCellRendererComponent(
JTable.this, null, false, false,
row, column);
}
// AccessibleContext methods
/**
* Get the accessible name of this object.
*
* @return the localized name of the object; null if this
* object does not have a name
*/
public String getAccessibleName() {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac != null) {
String name = ac.getAccessibleName();
if ((name != null) && (name != "")) {
return ac.getAccessibleName();
}
}
if ((accessibleName != null) && (accessibleName != "")) {
return accessibleName;
} else {
return parent.getValueAt(row, column).toString();
}
}
/**
* Set the localized accessible name of this object.
*
* @param s the new localized name of the object.
*/
public void setAccessibleName(String s) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac != null) {
ac.setAccessibleName(s);
} else {
super.setAccessibleName(s);
}
}
//
// *** should check toolip text for desc. (needs MouseEvent)
//
/**
* Get the accessible description of this object.
*
* @return the localized description of the object; null if
* this object does not have a description
*/
public String getAccessibleDescription() {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac != null) {
return ac.getAccessibleDescription();
} else {
return super.getAccessibleDescription();
}
}
/**
* Set the accessible description of this object.
*
* @param s the new localized description of the object
*/
public void setAccessibleDescription(String s) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac != null) {
ac.setAccessibleDescription(s);
} else {
super.setAccessibleDescription(s);
}
}
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the object
* @see AccessibleRole
*/
public AccessibleRole getAccessibleRole() {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac != null) {
return ac.getAccessibleRole();
} else {
return AccessibleRole.UNKNOWN;
}
}
/**
* Get the state set of this object.
*
* @return an instance of AccessibleStateSet containing the
* current state set of the object
* @see AccessibleState
*/
public AccessibleStateSet getAccessibleStateSet() {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac != null) {
return ac.getAccessibleStateSet();
} else {
return new AccessibleStateSet(); // must be non null?
}
}
/**
* Get the Accessible parent of this object.
*
* @return the Accessible parent of this object; null if this
* object does not have an Accessible parent
*/
public Accessible getAccessibleParent() {
return parent;
}
/**
* Get the index of this object in its accessible parent.
*
* @return the index of this object in its parent; -1 if this
* object does not have an accessible parent.
* @see #getAccessibleParent
*/
public int getAccessibleIndexInParent() {
return index;
}
/**
* Returns the number of accessible children in the object.
*
* @return the number of accessible children in the object.
*/
public int getAccessibleChildrenCount() {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac != null) {
return ac.getAccessibleChildrenCount();
} else {
return 0;
}
}
/**
* Return the specified Accessible child of the object.
*
* @param i zero-based index of child
* @return the Accessible child of the object
*/
public Accessible getAccessibleChild(int i) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac != null) {
Accessible accessibleChild = ac.getAccessibleChild(i);
ac.setAccessibleParent(this);
return accessibleChild;
} else {
return null;
}
}
/**
* Gets the locale of the component. If the component does not have a
* locale, then the locale of its parent is returned.
*
* @return This component's locale. If this component does not have a locale, the locale of its parent is returned.
* @exception IllegalComponentStateException
* If the Component does not have its own locale and has not yet been added to a containment hierarchy such that the locale can be
* determined from the containing parent.
* @see setLocale
*/
public Locale getLocale() {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac != null) {
return ac.getLocale();
} else {
return null;
}
}
/**
* Add a PropertyChangeListener to the listener list.
* The listener is registered for all properties.
*
* @param listener The PropertyChangeListener to be added
*/
public void addPropertyChangeListener(PropertyChangeListener l) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac != null) {
ac.addPropertyChangeListener(l);
} else {
super.addPropertyChangeListener(l);
}
}
/**
* Remove a PropertyChangeListener from the listener list.
* This removes a PropertyChangeListener that was registered
* for all properties.
*
* @param listener The PropertyChangeListener to be removed
*/
public void removePropertyChangeListener(PropertyChangeListener l) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac != null) {
ac.removePropertyChangeListener(l);
} else {
super.removePropertyChangeListener(l);
}
}
/**
* Get the AccessibleAction associated with this object if one
* exists. Otherwise return null.
*
* @return the AccessibleAction, or null
*/
public AccessibleAction getAccessibleAction() {
return getCurrentAccessibleContext().getAccessibleAction();
}
/**
* Get the AccessibleComponent associated with this object if one
* exists. Otherwise return null.
*
* @return the AccessibleComponent, or null
*/
public AccessibleComponent getAccessibleComponent() {
return this; // to override getBounds()
}
/**
* Get the AccessibleSelection associated with this object if one
* exists. Otherwise return null.
*
* @return the AccessibleSelection, or null
*/
public AccessibleSelection getAccessibleSelection() {
return getCurrentAccessibleContext().getAccessibleSelection();
}
/**
* Get the AccessibleText associated with this object if one
* exists. Otherwise return null.
*
* @return the AccessibleText, or null
*/
public AccessibleText getAccessibleText() {
return getCurrentAccessibleContext().getAccessibleText();
}
/**
* Get the AccessibleValue associated with this object if one
* exists. Otherwise return null.
*
* @return the AccessibleValue, or null
*/
public AccessibleValue getAccessibleValue() {
return getCurrentAccessibleContext().getAccessibleValue();
}
// AccessibleComponent methods
/**
* Get the background color of this object.
*
* @return the background color, if supported, of the object;
* otherwise, null
*/
public Color getBackground() {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
return ((AccessibleComponent) ac).getBackground();
} else {
Component c = getCurrentComponent();
if (c != null) {
return c.getBackground();
} else {
return null;
}
}
}
/**
* Set the background color of this object.
*
* @param c the new Color for the background
*/
public void setBackground(Color c) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
((AccessibleComponent) ac).setBackground(c);
} else {
Component cp = getCurrentComponent();
if (cp != null) {
cp.setBackground(c);
}
}
}
/**
* Get the foreground color of this object.
*
* @return the foreground color, if supported, of the object;
* otherwise, null
*/
public Color getForeground() {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
return ((AccessibleComponent) ac).getForeground();
} else {
Component c = getCurrentComponent();
if (c != null) {
return c.getForeground();
} else {
return null;
}
}
}
/**
* Set the foreground color of this object.
*
* @param c the new Color for the foreground
*/
public void setForeground(Color c) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
((AccessibleComponent) ac).setForeground(c);
} else {
Component cp = getCurrentComponent();
if (cp != null) {
cp.setForeground(c);
}
}
}
/**
* Get the Cursor of this object.
*
* @return the Cursor, if supported, of the object; otherwise, null
*/
public Cursor getCursor() {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
return ((AccessibleComponent) ac).getCursor();
} else {
Component c = getCurrentComponent();
if (c != null) {
return c.getCursor();
} else {
Accessible ap = getAccessibleParent();
if (ap instanceof AccessibleComponent) {
return ((AccessibleComponent) ap).getCursor();
} else {
return null;
}
}
}
}
/**
* Set the Cursor of this object.
*
* @param c the new Cursor for the object
*/
public void setCursor(Cursor c) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
((AccessibleComponent) ac).setCursor(c);
} else {
Component cp = getCurrentComponent();
if (cp != null) {
cp.setCursor(c);
}
}
}
/**
* Get the Font of this object.
*
* @return the Font,if supported, for the object; otherwise, null
*/
public Font getFont() {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
return ((AccessibleComponent) ac).getFont();
} else {
Component c = getCurrentComponent();
if (c != null) {
return c.getFont();
} else {
return null;
}
}
}
/**
* Set the Font of this object.
*
* @param f the new Font for the object
*/
public void setFont(Font f) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
((AccessibleComponent) ac).setFont(f);
} else {
Component c = getCurrentComponent();
if (c != null) {
c.setFont(f);
}
}
}
/**
* Get the FontMetrics of this object.
*
* @param f the Font
* @return the FontMetrics, if supported, the object; otherwise, null
* @see getFont
*/
public FontMetrics getFontMetrics(Font f) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
return ((AccessibleComponent) ac).getFontMetrics(f);
} else {
Component c = getCurrentComponent();
if (c != null) {
return c.getFontMetrics(f);
} else {
return null;
}
}
}
/**
* Determine if the object is enabled.
*
* @return true if object is enabled; otherwise, false
*/
public boolean isEnabled() {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
return ((AccessibleComponent) ac).isEnabled();
} else {
Component c = getCurrentComponent();
if (c != null) {
return c.isEnabled();
} else {
return false;
}
}
}
/**
* Set the enabled state of the object.
*
* @param b if true, enables this object; otherwise, disables it
*/
public void setEnabled(boolean b) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
((AccessibleComponent) ac).setEnabled(b);
} else {
Component c = getCurrentComponent();
if (c != null) {
c.setEnabled(b);
}
}
}
/**
* Determine if the object is visible. Note: this means that the
* object intends to be visible; however, it may not in fact be
* showing on the screen because one of the objects that this object
* is contained by is not visible. To determine if an object is
* showing on the screen, use isShowing().
*
* @return true if object is visible; otherwise, false
*/
public boolean isVisible() {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
return ((AccessibleComponent) ac).isVisible();
} else {
Component c = getCurrentComponent();
if (c != null) {
return c.isVisible();
} else {
return false;
}
}
}
/**
* Set the visible state of the object.
*
* @param b if true, shows this object; otherwise, hides it
*/
public void setVisible(boolean b) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
((AccessibleComponent) ac).setVisible(b);
} else {
Component c = getCurrentComponent();
if (c != null) {
c.setVisible(b);
}
}
}
/**
* Determine if the object is showing. This is determined by checking
* the visibility of the object and ancestors of the object. Note: this
* will return true even if the object is obscured by another (for example,
* it happens to be underneath a menu that was pulled down).
*
* @return true if object is showing; otherwise, false
*/
public boolean isShowing() {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
return ((AccessibleComponent) ac).isShowing();
} else {
Component c = getCurrentComponent();
if (c != null) {
return c.isShowing();
} else {
return false;
}
}
}
/**
* Checks whether the specified point is within this object's bounds,
* where the point's x and y coordinates are defined to be relative to the
* coordinate system of the object.
*
* @param p the Point relative to the coordinate system of the object
* @return true if object contains Point; otherwise false
*/
public boolean contains(Point p) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
Rectangle r = ((AccessibleComponent) ac).getBounds();
return r.contains(p);
} else {
Component c = getCurrentComponent();
if (c != null) {
Rectangle r = c.getBounds();
return r.contains(p);
} else {
return getBounds().contains(p);
}
}
}
/**
* Returns the location of the object on the screen.
*
* @return location of object on screen -- can be null if this object
* is not on the screen
*/
public Point getLocationOnScreen() {
if (parent != null) {
Point parentLocation = parent.getLocationOnScreen();
Point componentLocation = getLocation();
componentLocation.translate(parentLocation.x, parentLocation.y);
return componentLocation;
} else {
return null;
}
}
/**
* Gets the location of the object relative to the parent in the form
* of a point specifying the object's top-left corner in the screen's
* coordinate space.
*
* @return An instance of Point representing the top-left corner of the
* objects's bounds in the coordinate space of the screen; null if
* this object or its parent are not on the screen
*/
public Point getLocation() {
if (parent != null) {
Rectangle r = parent.getCellRect(row, column, false);
if (r != null) {
return r.getLocation();
}
}
return null;
}
/**
* Sets the location of the object relative to the parent.
*/
public void setLocation(Point p) {
// if ((parent != null) && (parent.contains(p))) {
// ensureIndexIsVisible(indexInParent);
// }
}
public Rectangle getBounds() {
if (parent != null) {
return parent.getCellRect(row, column, false);
} else {
return null;
}
}
public void setBounds(Rectangle r) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
((AccessibleComponent) ac).setBounds(r);
} else {
Component c = getCurrentComponent();
if (c != null) {
c.setBounds(r);
}
}
}
public Dimension getSize() {
if (parent != null) {
Rectangle r = parent.getCellRect(row, column, false);
if (r != null) {
return r.getSize();
}
}
return null;
}
public void setSize (Dimension d) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
((AccessibleComponent) ac).setSize(d);
} else {
Component c = getCurrentComponent();
if (c != null) {
c.setSize(d);
}
}
}
public Accessible getAccessibleAt(Point p) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
return ((AccessibleComponent) ac).getAccessibleAt(p);
} else {
return null;
}
}
public boolean isFocusTraversable() {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
return ((AccessibleComponent) ac).isFocusTraversable();
} else {
Component c = getCurrentComponent();
if (c != null) {
return c.isFocusTraversable();
} else {
return false;
}
}
}
public void requestFocus() {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
((AccessibleComponent) ac).requestFocus();
} else {
Component c = getCurrentComponent();
if (c != null) {
c.requestFocus();
}
}
}
public void addFocusListener(FocusListener l) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
((AccessibleComponent) ac).addFocusListener(l);
} else {
Component c = getCurrentComponent();
if (c != null) {
c.addFocusListener(l);
}
}
}
public void removeFocusListener(FocusListener l) {
AccessibleContext ac = getCurrentAccessibleContext();
if (ac instanceof AccessibleComponent) {
((AccessibleComponent) ac).removeFocusListener(l);
} else {
Component c = getCurrentComponent();
if (c != null) {
c.removeFocusListener(l);
}
}
}
} // inner class AccessibleJTableCell
} // inner class AccessibleJTable
} // End of Class JTable